import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

import '../log.dart';
import '../str_util.dart';

class OssResult {
  /// 文件名
  String fileName;

  /// 文件路径
  String filePath;

  /// 文件大小
  int fileSize;

  OssResult(
      {required this.fileName, required this.filePath, required this.fileSize});
}

/// OSS调用原生工具类
class OssNativeUtil {
  static const _methodChannelName = 'flutter.keqiang.com/oss';
  static const _eventChannelName = 'flutter.keqiang.com/ossEvent';

  static const _platformMethod = MethodChannel(_methodChannelName);

  static final Map<String, UploadProgressCallback?> _uploadCallbacks = {};
  static final _platformEvent = const EventChannel(_eventChannelName)
    ..receiveBroadcastStream().listen((event) {
      if (event is! Map) {
        return;
      }

      var callback = _uploadCallbacks[event['tag']];
      if (callback == null) {
        return;
      }
      int current = event['currentSize'];
      int total = event['totalSize'];
      callback.call(current, total);
    });

  /// 初始化
  static Future initOSS({required String bucketName}) async {
    try {
      await _platformMethod.invokeMethod('initOSS', {'bucketName': bucketName});
    } on PlatformException catch (e, stacktrace) {
      if (kDebugMode) {
        print(e);
        print(stacktrace);
      }
    }
    return;
  }

  /// 阿里云获取缓存文件，返回文件路径
  static Future<OssResult?> getOssCacheFile({
    required String ossKey,
    double? width,
    double? height,
  }) async {
    try {
      var result = await _platformMethod.invokeMethod('getOssCacheFile', {
        'ossKey': ossKey,
        'width': width,
        'height': height,
      });
      if (result['code'] == 1) {
        var data = result['data'];
        return OssResult(
            fileName: data['fileName'],
            filePath: data['filePath'],
            fileSize: data['fileSize']);
      } else {
        Log.d(result['msg'], tag: "OssNativeUtil");
        return null;
      }
    } on PlatformException catch (e, stacktrace) {
      if (kDebugMode) {
        print(e);
        print(stacktrace);
      }
    }
    return null;
  }

  /// 阿里云下载图片，返回图片路径
  static Future<OssResult?> ossDownloadImage(
      {required String ossKey,
      double? width,
      double? height,
      String? quality,
      BoxFit scaleType = BoxFit.none,
      String? tag}) async {
    try {
      var result = await _platformMethod.invokeMethod('ossDownloadImage', {
        'ossKey': ossKey,
        'width': width,
        'height': height,
        'quality': quality,
        'scaleType': scaleType.name,
        'tag': tag,
      });
      if (result['code'] == 1) {
        var data = result['data'];
        return OssResult(
            fileName: data['fileName'],
            filePath: data['filePath'],
            fileSize: data['fileSize']);
      } else {
        Log.d(result['msg'], tag: "OssNativeUtil");
        return null;
      }
    } on PlatformException catch (e, stacktrace) {
      if (kDebugMode) {
        print(e);
        print(stacktrace);
      }
    }
    return null;
  }

  /// 阿里云删除图片，返回是否成功
  static Future<bool> ossDelete({required String ossKey}) async {
    try {
      var result =
          await _platformMethod.invokeMethod('ossDelete', {'ossKey': ossKey});
      if (result['code'] == 1) {
        return true;
      } else {
        Log.d(result['msg'], tag: "OssNativeUtil");
        return false;
      }
    } on PlatformException catch (e, stacktrace) {
      if (kDebugMode) {
        print(e);
        print(stacktrace);
      }
    }
    return false;
  }

  /// 阿里云取消下载
  static Future ossCancelDownload({required String tag}) async {
    try {
      await _platformMethod.invokeMethod('ossCancelDownload', {
        'tag': tag,
      });
    } on PlatformException catch (e, stacktrace) {
      if (kDebugMode) {
        print(e);
        print(stacktrace);
      }
    }
  }

  /// 批量上传图片到OSS
  ///
  /// ossKeyAndPaths数据格式：[{'ossKey' : '',  'filePath': '', 'uploadOk': false}]。ossKey为文件上传到OSS的路径，
  /// filePath为本地需要上传的图片文件路径。uploadOk为false时执行上传，否则直接返回。ossKeyAndPaths对象属性除了ossKey,filePath
  /// 和uploadOk外，可以加自定义属性，最终会通过返回参数原封不动返回。
  ///
  /// 返回数据格式：[{'ossKey' : '',  'filePath': '', 'uploadOk': true, 'fileName': 'xx.png', 'fileSize': 1000}]。
  /// 存在上传失败的图片，则uploadOk为false。fileName和fileSize仅执行上传操作且上传成功的图片会返回此属性。
  /// 返回数据数量与[ossKeyAndPaths]保持一致。
  static Future<List<Map<String, dynamic>>?> uploadPics(
      List<Map<String, dynamic>> ossKeyAndPaths) async {
    if (ossKeyAndPaths.isEmpty) {
      return null;
    }
    try {
      List<dynamic> result = await _platformMethod
          .invokeMethod('ossUploadPics', {'ossKeyAndPaths': ossKeyAndPaths});
      return result
          .cast<Map<dynamic, dynamic>>()
          .map((e) => e.cast<String, dynamic>())
          .toList();
    } on PlatformException catch (e, stacktrace) {
      if (kDebugMode) {
        print(e);
        print(stacktrace);
      }
      return null;
    }
  }

  /// 上传单个文件到OSS
  ///
  /// [ossKey]为文件保存到OSS地址，[filePath]为本地需要上传文件地址，[mime]为本地上传文件类型
  static Future<bool> uploadSingleFile(String ossKey, String filePath,
      {String? mime, UploadProgressCallback? uploadProgress}) async {
    var tag = uploadProgress == null ? null : StrUtil.uuid();
    if (tag != null) {
      /// 在 ios 不调用该方法是不会执行..receiveBroadcastStream
      _platformEvent;
      _uploadCallbacks[tag] = uploadProgress;
    }

    var result = await _platformMethod.invokeMethod('ossUploadFile',
        {'ossKey': ossKey, 'filePath': filePath, 'mime': mime, 'tag': tag});

    if (tag != null) {
      _uploadCallbacks.remove(tag);
    }

    if (result['code'] == 1) {
      return true;
    } else {
      Log.d(result['msg'], tag: "OssNativeUtil");
      return false;
    }
  }
}

typedef UploadProgressCallback = Function(int current, int total);
